/**
 *
 */
package com.mperon.util.io;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;



/**
 * @author Marcos Peron
 *
 */
public class FileLister {

    /**
     *
     */
    public FileLister() {
        super();
    }
    
    
    public List<File> listFiles(File directory, FilenameFilter filter, boolean isRecursive) throws FileNotFoundException {
        List<File> result = null;
        if (directory.exists() && directory.isDirectory()) {
            result = processDir(directory, filter, isRecursive);
        } else {
            throw new FileNotFoundException("Directory " + directory +  " doesnt exists!");
        } 
        return(result);
    }
    
    public List<File> listFiles(File directory, FilenameFilter filter) throws FileNotFoundException {    
        return(listFiles(directory, filter, true));
    }
    
    public List<File> listFiles(String directory, FilenameFilter filter, boolean isRecursive) throws FileNotFoundException {
        return(listFiles(new File(directory), filter, isRecursive));                    
    }

    public List<File> listFiles(String directory, String fileFilter, boolean isRecursive, boolean isRegExpr) throws FileNotFoundException {
        PathPattern f = new PathPattern(fileFilter, isRegExpr, isRecursive);
        return listFiles(directory, f, isRecursive);
    }

    private List<File> processDir(File dir, FilenameFilter filter, boolean isRecursive) {
        File[] lista = dir.listFiles(filter);
        List<File> files = new ArrayList<File>();
        for (int i = 0; i < lista.length; i++) {
            File elem = lista[i];
            if (elem.isDirectory()) {
                if (isRecursive) {
                    List<File> tmp = processDir(elem, filter, isRecursive);
                    files.addAll(tmp);
                }
            } else {
                files.add(elem);
            }
        }
        return files;
    }

    private class PathPattern implements FilenameFilter {

        private List<String> patterns;
        private boolean regexp;
        private boolean acceptdir;

        public PathPattern(String fileFilter, boolean regexp, boolean acceptdir) {
            patterns = new ArrayList<String>();
            this.acceptdir = acceptdir;
            this.setPatterns(fileFilter);
            this.regexp = regexp;
        }

        public boolean accept(File dir, String name) {
            if (acceptdir) {
                File f = new File(dir.getAbsolutePath() + File.separatorChar + name);
                if (f.exists() && f.isDirectory()) {
                    return true;
                }
            }
            return validate(name);
        }

        private boolean validate(String name) {
            boolean result = false;
            boolean bMatch = false;
            for (Iterator<String> iter = patterns.iterator(); iter.hasNext();) {
                String element = (String) iter.next();
                bMatch = Pattern.matches(element, name);
                if (bMatch) {
                    result = true;
                    break;
                }
            }
            return result;
        }

        private void setPatterns(String fileFilter) {
            String aux = fileFilter;
            if (!regexp) {
                //configura a explressao regular
                //aux = "^" + aux;
                aux = aux.replace("\\", "\\\\");
                aux = aux.replace("[", "\\[");
                aux = aux.replace("]", "\\]");
                aux = aux.replace(".", "[.]{1}");
                aux = aux.replace("*", ".*");
                aux = aux.replace("?", ".{1}");
                //aux = aux + "$";
            }
            patterns.clear();
            String[] auxiliar = aux.split(";");
            for (int i = 0; i < auxiliar.length; i++) {
                String str = auxiliar[i];
                patterns.add(str);
            }
        }
    }
}